package xueqiu

import (
	"fmt"
	"gitee.com/gcom/gbox/errors"
	"gitee.com/gcom/stockdock/comm"
	s "gitee.com/gcom/stockdock/core/support"
	"gitee.com/gcom/stockdock/crawler"
	"gitee.com/gcom/stockdock/spider/csrc"
	"gitee.com/gcom/stockdock/spider/xueqiu"
	"time"
)

// UpdateDailyQuoteHist 更新雪球股票历史日报价
func UpdateDailyQuoteHist(ctx s.TracerCtx) error {
	list, err := csrc.GetStockAll(ctx.DB)
	if err != nil {
		s.WriteErrEvent(ctx, "查询股票失败", err)
		return err
	}
	s.WriteEvent(ctx, fmt.Sprintf("共计股票%d支", len(list)))

	var count, nodata, total = 0, 0, len(list)
	var codeCh = make(chan string)
	var sem = make(chan int)
	defer close(codeCh)
	onValue := func(req crawler.CrawlRequest, quotes []*xueqiu.DailyQuoteHist) {
		var r = req.(*xueqiu.DailyQuoteHistCrawlRequest)
		if len(quotes) == 0 {
			nodata += 1
			s.WriteEvent(ctx, fmt.Sprintf("[%d,%d/%d]获取股票(%s)无历史报价数据", count, nodata, total, r.Code))
		} else {
			count += 1
			s.WriteEvent(ctx, fmt.Sprintf("[%d,%d/%d]已获取股票(%s)历史报价%d条", count, nodata, total, r.Code, len(quotes)))

			var entities = make([]*xueqiu.DailyQuoteHistEntity, len(quotes))
			for i, v := range quotes {
				entities[i] = &xueqiu.DailyQuoteHistEntity{DailyQuoteHist: v}
			}
			_, err = xueqiu.UpdateStockQuoteHist(ctx.DB, entities)
			if err != nil {
				s.WriteErrEvent(ctx, "写入数据库失败", err)
				close(sem)
				return
			}
			s.WriteEvent(ctx, fmt.Sprintf("[%d,%d/%d]写入数据库%d条", count, nodata, total, len(entities)))
		}

		sem <- 1 // produce one ticket
	}
	onError := func(req crawler.CrawlRequest, err error) {
		s.WriteErrEvent(ctx, "获取股票历史报价失败", err)
		close(sem)
	}

	go func() {
		xueqiu.GetStockHistQuote(ctx, codeCh, onValue, onError)
	}()

	// 获取股票报价
	for i, v := range list {
		codeCh <- comm.StockSymbol(v.Code)

		select {
		case _, ok := <-sem: // consume 1 ticket
			if !ok {
				err := errors.New(fmt.Sprintf("异常退出，共完成写入股票%d支，无数据%d支，总共%d支", count, nodata, total))
				s.WriteErrEvent(ctx, "异常退出", err)
				return err // task aborted
			}
		}

		if i == total-1 {
			close(sem)
			s.WriteEvent(ctx, fmt.Sprintf("共完成写入股票%d支，无数据%d支，总共%d支", count, nodata, total))
			return nil
		}

		time.Sleep(500 * time.Millisecond)
	}
	return nil
}
